/**
 * @file hs_c11ext.h
 * @author iam002 
 * @brief 扩展C11标准
 * @version 1.0
 * @date 2024-10-14
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#ifndef __HS_C11EXT_H__
#define __HS_C11EXT_H__

#include <type_traits>
#include <utility>
#include <ostream>
#include <ios>
#include <locale>
#include <iterator>

/**
 * @brief 建议: 
 * 将扩展的代码放置于条件宏内
 * #ifdef HS_USE_CXX_STANDARD_11
 *      (扩展代码) ...
 * #else
 *      ...
 * #endif
 * 
 */
// #define HS_USE_CXX_STANDARD_11

namespace hs
{

namespace c11ext
{

/**
 * @brief C++11下实现编译分支
 * 
 * @note 通过下面的宏进行调用
 *  C11EXT_IF_CONSTEXPR(condition) {
 *      ...
 *  } C11EXT_ELSE_CONSTEXPR {
 *      ...
 *  } C11EXT_ENDIF_CONSTEXPR
 * 
 * @note 由于{...}本质上是一个匿名函数, 请不要在 {...} 使用 return
 *       作为外部的函数的返回值(实际上是匿名函数的返回值), 否则可能
 *       导致程序出现错误的结果.
 */
struct identity {
    template <typename T>
    T operator()(T&& x) const {
        return std::forward<T>(x);
    }
};

template<bool Cond>
struct statement {
    template <typename F>
    void then(const F& f) {
        f(identity());
    }

    template <typename F>
    void else_(const F&) {}
};

template<>
struct statement<false> {
    template <typename F>
    void then(const F&) {}

    template <typename F>
    void else_(const F& f) {
        f(identity());
    }
};

template<bool Cond, typename F>
statement<Cond> if_constexpr(F const& f) {
    statement<Cond> if_;
    if_.then(f);
    return if_;
}

#define C11EXT_IF_CONSTEXPR(A) hs::c11ext::if_constexpr<A>([&](hs::c11ext::identity)
#define C11EXT_ELSE_CONSTEXPR ).else_([&](hs::c11ext::identity)
#define C11EXT_ENDIF_CONSTEXPR );

/**
 * @brief C++11 实现 std::index_sequece
 * 
 */
template<std::size_t... Ints>
struct index_sequence {};

template<std::size_t N, std::size_t... Ints>
struct make_index_sequence_impl : make_index_sequence_impl<N-1, N-1, Ints...> {};

template<std::size_t... Ints>
struct make_index_sequence_impl<0, Ints...> {
    using type = index_sequence<Ints...>;
};

template<std::size_t N>
using make_index_sequence = typename make_index_sequence_impl<N>::type;

/**
 * @brief gcc4.8.5 实现 std::put_time
 * 
 */
template<typename CharT>
struct _put_time                   
{                                                                     
    const std::tm* time;
    const char *fmt;
};
    
template<typename CharT>
inline _put_time<CharT>
put_time(const std::tm* time, const CharT* fmt)
{ 
    return { time, fmt };
}
  
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits> &os, _put_time<CharT> f)
{   
    typedef typename std::ostreambuf_iterator<CharT, Traits> Iter;
    typedef std::time_put<CharT, Iter> TimePut;
        
    const CharT* const fmt_end = f.fmt + Traits::length(f.fmt);
    const TimePut& mp = std::use_facet<TimePut>(os.getloc());

    std::ios_base::iostate err = std::ios_base::goodbit;
    try {
    if (mp.put(Iter(os.rdbuf()), os, os.fill(), f.time, f.fmt, fmt_end).failed())
        err |= std::ios_base::badbit;
    }
    catch (...) {
    err |= std::ios_base::badbit;
    }  

    if (err)
    os.setstate(err);

    return os;
} 

} // end namespace c11ext

} // end namespace hs

#endif
